package com.sjsoft.services.download;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import com.sjsoft.interfaces.OnDownloadCompleteListener;
import com.sjsoft.interfaces.OnDownloadStartListener;
import com.sjsoft.model.IDownloadedItem;

import android.content.Context;
import android.os.Environment;
import android.util.Log;

public class DownloadThread extends Thread {

	private final Context context;
	private IDownloadedItem item;
	public static final int ACTION_DOWNLOADING = 4;
	public static final int ACTION_COMPLETE = 2;
	public static final int ACTION_CANCELLED = 3;
	private static final String FOLDER_PATH = "/Zinzin/install/" ;
	public static int downloadCount = 0;
	public static int notificationId = 0;
	private int downloadId;
	public static int state = 0;
	private int downloaded = 0;
	private int size;
	private int percent;
	private OnDownloadCompleteListener onDownloadCompleteListener;
	private OnDownloadStartListener onDownloadStartListener;

	public DownloadThread(Context context, IDownloadedItem downloadedItem) {
		this.context = context;
		downloadCount++;
		this.downloadId = downloadCount;
		this.item = downloadedItem;
		this.start();
	}

	@Override
	public void run() {
		try {
			onPreExecute();
			onPostExecute(doInBackground());
		} finally {
			this.interrupt();
		}
	}

	protected File doInBackground() {
		if (item != null) {
			try {
				return retrieveContent(item);
			} catch (IOException ex) {
				handleError();
				return null;
			} catch (OutOfMemoryError e) {
				handleMemory();
				return null;
			} catch (Exception e) {
				handleData();
				return null;
			}
		}
		return null;
	}

	public int getPercent() {
		return percent;
	}

	protected void onCancelled() {
		// Log.d("asdf", "onCancelled");

		state = ACTION_CANCELLED;
		ServiceQueueDownloadUtil.notifyDownloadMessage(context, item
				.getFileName()
				+ ": " + ServiceQueueDownloadUtil.MESSAGE_ERROR, downloadId,
				item.getName(), (byte) 2);
		deleteFailedDownloadedFile(item);

	}

	protected void onCancelledAll() {
		state = ACTION_CANCELLED;
		if (!item.getState())
			ServiceQueueDownloadUtil.notifyDownloadMessage(context, item
					.getFileName()
					+ ": " + ServiceQueueDownloadUtil.MESSAGE_ERROR,
					downloadId, item.getName(), (byte) 2);
		for (int i = downloadId + 1; i <= notificationId; i++) {
			item = ServiceQueueDownloadUtil.downloadQueue.remove();
			if (!item.getState())
				ServiceQueueDownloadUtil.notifyDownloadMessage(context, item
						.getFileName()
						+ ": " + ServiceQueueDownloadUtil.MESSAGE_ERROR, i,
						item.getName(), (byte) 2);
		}
		downloadCount = notificationId;
	}

	protected void onPostExecute(File result) {
		state = ACTION_COMPLETE;
		if (result == null) {
			ServiceQueueDownloadUtil.notifyDownloadMessage(context, item
					.getFileName()
					+ ": " + ServiceQueueDownloadUtil.MESSAGE_ERROR,
					downloadId, item.getName(), (byte) 2);
			deleteFailedDownloadedFile(item);
			if (ServiceQueueDownloadUtil.downloadQueue != null) {
				ServiceQueueDownloadUtil.runDownloadQueue(context);
			}
		} else {
			if (size == downloaded) {
				if (onDownloadCompleteListener != null) {
					onDownloadCompleteListener
							.onDownloadComplete(context, item);
				}
				ServiceQueueDownloadUtil.notifyDownloadMessage(context, item
						.getFileName()
						+ ": " + ServiceQueueDownloadUtil.MESSAGE_COMPLETE,
						downloadId, item.getName(), (byte) 0);
			} else {
				ServiceQueueDownloadUtil.notifyDownloadMessage(context, item
						.getFileName()
						+ ": " + ServiceQueueDownloadUtil.MESSAGE_ERROR,
						downloadId, item.getName(), (byte) 2);
				deleteFailedDownloadedFile(item);
			}
		}
		if (ServiceQueueDownloadUtil.downloadQueue != null) {
			ServiceQueueDownloadUtil.runDownloadQueue(context);
		}
	}

	protected void onPreExecute() {

		state = ACTION_DOWNLOADING;
		downloaded = 0;
		if (onDownloadStartListener != null) {
			onDownloadStartListener.onDownloadStart(item);
		}
	}

	protected void onProgressUpdate(Integer values) {
		if (item != null) {
			percent = Math
					.round(((float) values / ((float) item.getFileSize())) * 100);
			String message = percent + "%";
			ServiceQueueDownloadUtil.notifyDownloadMessage(context, item
					.getFileName()
					+ ": " + message, downloadId, item.getName(), (byte) 1);
			if (state == ACTION_CANCELLED) {
				ServiceQueueDownloadUtil.notifyDownloadMessage(context, item
						.getFileName()
						+ ": " + ServiceQueueDownloadUtil.MESSAGE_ERROR,
						downloadId, item.getName(), (byte) 2);
				deleteFailedDownloadedFile(item);
				if (ServiceQueueDownloadUtil.downloadQueue != null) {
					ServiceQueueDownloadUtil.runDownloadQueue(context);
				}
			}
		}
	}

	private File retrieveContent(IDownloadedItem item) throws OutOfMemoryError,
			IOException, Exception {
		String stateCheck = android.os.Environment.getExternalStorageState();
		if (!stateCheck.equals(android.os.Environment.MEDIA_MOUNTED)) {
			state = ACTION_CANCELLED;
			ServiceQueueDownloadUtil.cancelTask();
			ServiceQueueDownloadUtil.notifyDownloadMessage(context, item
					.getFileName()
					+ ": " + ServiceQueueDownloadUtil.MESSAGE_ERROR,
					downloadId, item.getName(), (byte) 2);
			return null;
		}
		File file;

		String filename = "";
		if (Environment.MEDIA_MOUNTED.equals(Environment
				.getExternalStorageState())) {
			filename = Environment.getExternalStorageDirectory()
					+ FOLDER_PATH + item.getFileName();
			file = new File(filename);
			if (file.exists()) {
				file.delete();
			}
		} else {
			// apparently on some configurations this can come back as null
			File internalCacheDir = context.getCacheDir();
			if (internalCacheDir == null) {
			} else {
				filename = internalCacheDir.getAbsolutePath()
						+ FOLDER_PATH + item.getFileName();
				file = new File(filename);
				if (file.exists()) {
					file.delete();
				}

			}

		}

		return downloadFile(item.getUrl(), filename);
	}

	private byte count = 0;

	private File downloadFile(String url, String fileName)
			throws OutOfMemoryError, IOException, Exception {
		InputStream is = null;
		BufferedInputStream bis = null;
		FileOutputStream fos = null;
		File file = null;
		try {
			file = new File(fileName);
			file.getParentFile().mkdirs();
			file.createNewFile();
			/* Open a connection to that URL. */
			is = ServiceQueueDownloadUtil.getDownloadStream(url, item);
			if (is == null) {
				return null;
			}
			
			size = item.getFileSize();
			Log.w("size", ""+size);
			bis = new BufferedInputStream(is);
			byte[] buff = new byte[16384];

			if (state == ACTION_DOWNLOADING) {
				fos = new FileOutputStream(fileName, true);
				int byteRead = -1;
				do {
					byteRead = bis.read(buff);

					if ((byteRead == -1) || (size <= downloaded)) {
						break;
					}
					downloaded += byteRead;
					fos.write(buff, 0, byteRead);
					count++;
					if (count > 19) {
						count = 0;
						onProgressUpdate(downloaded);
					}
					try {
						Thread.sleep(100);
					} catch (Exception ignore) {
					}
				} while (byteRead != -1 && state == ACTION_DOWNLOADING);
			}
			if (state == ACTION_DOWNLOADING) {
				state = ACTION_COMPLETE;
				onProgressUpdate(downloaded);
				return file;
			} else {
				return null;
			}

		} catch (IOException e) {
			try {
				file.delete();
			} catch (Exception ignore) {
			}
			throw e;
		} catch (OutOfMemoryError e) {
			try {
				file.delete();
			} catch (Exception ignore) {
			}
			throw e;
		} catch (Exception e) {
			try {
				file.delete();
			} catch (Exception ignore) {
			}
			throw e;
		} finally {
			try {
				is.close();
			} catch (Exception ignore) {
			}
			try {
				bis.close();
			} catch (Exception ignore) {
			}
			try {
				if (fos != null)
					fos.close();
			} catch (Exception ignore) {
			}
		}
		// return null;
	}

	public OnDownloadCompleteListener getOnDownloadCompleteListener() {
		return onDownloadCompleteListener;
	}

	public void setOnDownloadCompleteListener(
			OnDownloadCompleteListener onDownloadCompleteListener) {
		this.onDownloadCompleteListener = onDownloadCompleteListener;
	}

	public OnDownloadStartListener getOnDownloadStartListener() {
		return onDownloadStartListener;
	}

	public void setOnDownloadStartListener(
			OnDownloadStartListener onDownloadStartListener) {
		this.onDownloadStartListener = onDownloadStartListener;
	}

	private void handleError() {
		state = ACTION_CANCELLED;
		ServiceQueueDownloadUtil.cancelTask();
		ServiceQueueDownloadUtil.notifyDownloadMessage(context, item
				.getFileName()
				+ ": " + ServiceQueueDownloadUtil.MESSAGE_ERROR, downloadId,
				item
				.getFileName(), (byte) 2);
		deleteFailedDownloadedFile(item);
	}

	private void handleData() {
		state = ACTION_CANCELLED;
		ServiceQueueDownloadUtil.cancelTask();
		ServiceQueueDownloadUtil.notifyDownloadMessage(context, item
				.getFileName()
				+ ": " + ServiceQueueDownloadUtil.MESSAGE_ERROR, downloadId,
				item
				.getFileName(), (byte) 2);
		deleteFailedDownloadedFile(item);
	}

	private void handleMemory() {
		state = ACTION_CANCELLED;
		ServiceQueueDownloadUtil.cancelTask();
		ServiceQueueDownloadUtil.notifyDownloadMessage(context, item
				.getFileName()
				+ ": " + ServiceQueueDownloadUtil.MESSAGE_ERROR, downloadId,
				item
				.getFileName(), (byte) 2);
		deleteFailedDownloadedFile(item);
	}

	private void deleteFailedDownloadedFile(IDownloadedItem item) {
		File tmpFile = new File(Environment.getExternalStorageDirectory()
				+ FOLDER_PATH + item.getFileName());
		if (tmpFile.exists()) {
			tmpFile.delete();
		}
	}
}
